package network;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedList;

import map.Item;
import map.Level;
import map.Lightmap;
import objects.Enemy;
import objects.Player;
import battle.BattleResult;

public class Client {

	private int clientPort;
	private String serverIp;
	private int serverPort;
	private int userId;

	private LinkedList<Player> listPlayers;
	private LinkedList<Enemy> listEnemies;
	private LinkedList<Item> listItems;
	private Player player;

	private boolean roomUpdate;
	private Level serverLevel;

	public Client(String serverIp, int serverPort, int clientPort, Player player, int userId) {
		this.listPlayers = new LinkedList<Player>();
		this.listItems = new LinkedList<Item>();
		this.roomUpdate = false;
		this.serverIp = serverIp;
		this.serverPort = serverPort;
		this.clientPort = clientPort;
		this.userId = userId;
		this.player = player;
		listen();

	}

	public void itemPickUpAction(Player player) {
		sendItemPickUp(player);
	}

	public void readyAction(Player player, int newLevelIndex) {
		sendReady(player, newLevelIndex);
	}

	public Level loginAction(Player player) {
		return sendLogin(player, Commands.LOGIN);
	}

	public boolean moveAction(Player player, Lightmap lightmap) {
		return sendMove(player, lightmap, Commands.MOVE);
	}

	public BattleResult attackAction(Player player) {
		System.out.println(player.getCoord().getX() + " / " + player.getCoord().getY());
		return sendAttack(player);
	}

	private void sendItemPickUp(Player player) {
		Socket socket;
		try {
			socket = new Socket(serverIp, serverPort);
			ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
			objectOutputStream.writeObject(new UserAction(player, Commands.ITEMPICKUP, socket.getLocalAddress(), clientPort, userId));
			objectOutputStream.close();
			socket.close();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void sendReady(Player player, int newLevelIndex) {
		Socket socket;
		try {
			socket = new Socket(serverIp, serverPort);
			ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
			UserAction userAction = new UserAction(player, Commands.READY, socket.getLocalAddress(), clientPort, userId);
			userAction.setNewLevelIndex(newLevelIndex);
			objectOutputStream.writeObject(userAction);
			objectOutputStream.close();
			socket.close();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	private BattleResult sendAttack(final Player player) {

		BattleResult battleResult = null;

		try {
			Socket socket = new Socket(serverIp, serverPort);
			ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
			System.out.println(player.getCoord().getX() + " / " + player.getCoord().getY());
			objectOutputStream.writeObject(new UserAction(player, Commands.ATTACK, socket.getLocalAddress(), clientPort, userId));

			ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());

			battleResult = (BattleResult) objectInputStream.readObject();

			objectOutputStream.close();
			objectInputStream.close();
			socket.close();

		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		return battleResult;
	}

	private boolean sendMove(final Player player, final Lightmap lightmap, final Commands command) {
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					Socket socket = new Socket(serverIp, serverPort);
					ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
					UserAction userAction = new UserAction(player, command, socket.getLocalAddress(), clientPort, userId);
					userAction.setLightmap(lightmap);
					objectOutputStream.writeObject(userAction);

					objectOutputStream.close();
					socket.close();

				} catch (UnknownHostException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		}).start();
		boolean result = false;

		return result;
	}

	private Level sendLogin(Player player, Commands command) {
		Level resultRoom = null;
		try {
			Socket socket = new Socket(serverIp, serverPort);
			ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
			objectOutputStream.writeObject(new UserAction(player, command, socket.getLocalAddress(), this.clientPort, this.userId));
			ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
			try {
				resultRoom = (Level) objectInputStream.readObject();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
			objectInputStream.close();
			objectOutputStream.close();
			socket.close();

		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return resultRoom;
	}

	private void listen() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					ServerSocket serverSocket = new ServerSocket(clientPort);
					System.out.println("listening on port " + clientPort);
					while (true) {
						Socket socket = serverSocket.accept();
						ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
						ServerPackage serverPackage = null;
						try {
							serverPackage = (ServerPackage) objectInputStream.readObject();
						} catch (ClassNotFoundException e) {
							e.printStackTrace();
						}

						if (serverPackage != null) {
							System.out.println(serverPackage.getCommand().getCommand());
							if (serverPackage.getCommand() == Commands.SEND_LOCATIONS) {
								listPlayers = serverPackage.getListPlayers();
								for (Player listPlayer : listPlayers) {
									if (listPlayer.getUserId() == userId) {
										player.setCurHp(listPlayer.getCurHp());
										break;
									}
								}
								listEnemies = serverPackage.getListEnemies();
								listItems = serverPackage.getListItems();
								if (serverPackage.getLevel() != null) {
									serverLevel = serverPackage.getLevel();
									roomUpdate = true;
								}
							} else if (serverPackage.getCommand() == Commands.SEND_MAP) {
								listPlayers = serverPackage.getListPlayers();
								listEnemies = serverPackage.getListEnemies();
								listItems = serverPackage.getListItems();
								serverLevel = serverPackage.getLevel();
								for (Player listPlayer : listPlayers) {
									if (listPlayer.getUserId() == userId) {
										player.setCurLevelIndex(listPlayer.getCurLevelIndex());
										break;
									}
								}
								roomUpdate = true;
							}
						}

						objectInputStream.close();
						socket.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		}).start();
	}


	public int getClientId() {
		return userId;
	}

	public boolean isRoomUpdate() {
		return roomUpdate;
	}

	public void setRoomUpdate(boolean roomUpdate) {
		this.roomUpdate = roomUpdate;
	}

	public LinkedList<Player> getListPlayers() {
		return listPlayers;
	}

	public void setListPlayers(LinkedList<Player> listPlayers) {
		this.listPlayers = listPlayers;
	}

	public LinkedList<Enemy> getListEnemies() {
		return listEnemies;
	}

	public void setListEnemies(LinkedList<Enemy> listEnemies) {
		this.listEnemies = listEnemies;
	}

	public Level getServerLevel() {
		return serverLevel;
	}

	public LinkedList<Item> getListItems() {
		return listItems;
	}

	public Player getPlayer() {
		return player;
	}

}
